package io.github.sidvenu.mathjaxview;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.webengine.ResourceRequest;
import ohos.agp.components.webengine.ResourceResponse;
import ohos.agp.components.webengine.WebAgent;
import ohos.agp.components.webengine.WebView;
import ohos.agp.utils.TextTool;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.Resource;
import ohos.global.resource.WrongTypeException;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.net.Uri;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.net.URLConnection;

/**
 * 自定义Webview
 */
public class MathJaxView extends WebView implements Component.TouchEventListener {
    private String mText;
    private String config;
    private String preDefinedConfig;
    private final Context mContext;

    private final static String DEFINED_CONFIG = "TeX-MML-AM_CHTML";
    private final static String CHARSET = "utf-8";

    public MathJaxView(Context context, AttrSet attrs) {
        super(context, attrs);
        this.mContext = context;
        String xmlText = null;
        // if text is set in XML, call setText() with that text
        if (attrs.getAttr("text").isPresent()) {
            xmlText = attrs.getAttr("text").get().getStringValue();
        }
        String jsSchema;
        String defaultConfig;

        try {
            jsSchema = mContext.getResourceManager().getElement(ResourceTable.String_js_mhchem).getString();
            defaultConfig = mContext.getResourceManager().getElement(ResourceTable.String_default_config).getString();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.printStackTrace();
            return;
        }

        setConfig(
                String.format(defaultConfig, jsSchema)
        );

        preDefinedConfig = DEFINED_CONFIG;
        if (!TextTool.isNullOrEmpty(xmlText)) {
            setText(xmlText);
        }
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(new RgbColor(0, 0, 0, 0));
        setBackground(shapeElement);

        setWebViewConfig();
    }

    private void setWebViewConfig() {
        getWebConfig().setJavaScriptPermit(true);
        // getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);

        getWebConfig().setDataAbilityPermit(false);

        // Sets the security policy for the WebView to load resources
        // render MathJax once page finishes loading
        setWebAgent(new WebAgent() {

            @Override
            public void onPageLoaded(WebView webView, String url) {
                String javascript;
                try {
                    javascript = mContext.getResourceManager().getElement(ResourceTable.String_javascript).getString();
                } catch (IOException | NotExistException | WrongTypeException e) {
                    e.printStackTrace();
                    return;
                }
                webView.load(javascript);
            }

            @Override
            public ResourceResponse processResourceRequest(WebView webView, ResourceRequest request) {

                String authority;
                String rawFile;
                String resFile;

                try {
                    authority = mContext.getResourceManager().getElement(ResourceTable.String_authority).getString();
                    rawFile = mContext.getResourceManager().getElement(ResourceTable.String_raw_file).getString();
                    resFile = mContext.getResourceManager().getElement(ResourceTable.String_res_file).getString();
                } catch (IOException | NotExistException | WrongTypeException e) {
                    return super.processResourceRequest(webView, request);
                }

                Uri requestUri = request.getRequestUrl();
                if (authority.equals(requestUri.getDecodedAuthority())) {
                    String path = requestUri.getDecodedPath();

                    if (TextTool.isNullOrEmpty(path)) {
                        return super.processResourceRequest(webView, request);
                    }
                    if (path.startsWith(rawFile)) {
                        // 兼容一下字体文件
                        if (path.endsWith(".otf") || path.endsWith(".woff")) {
                            path = path.replaceAll("otf", "woff");
                        }

                        // 根据自定义规则访问资源文件
                        String rawFilePath = resFile + path.replace(rawFile, "");
                        String mimeType = URLConnection.guessContentTypeFromName(rawFilePath);
                        try {
                            Resource resource = getResourceManager().getRawFileEntry(rawFilePath).openRawFile();
                            return new ResourceResponse(mimeType, resource, CHARSET);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                return super.processResourceRequest(webView, request);
            }
        });

    }


    /**
     * I have included a default config that will be convenient for most of the people.
     * If you need to edit that config , please use this method to set your own MathJax custom config,
     * and note to call this before calling setText(String)
     *
     * @param config MathJax configuration to be used
     */
    public void setConfig(String config) {
        this.config = minifyConfig(config);
    }

    /**
     * This is to include any predefined MathJax configurations in the project, as referenced by
     * http://docs.mathjax.org/en/latest/config-files.html#common-configurations.
     * Only TeX-MML-AM_CHTML and MMLorHTML configurations comes with the assets of this project.
     * If you want other assets, create a MathJax folder in your application's assets, and
     * paste the config file in assets/MathJax/config/ folder.
     *
     * @param predefinedConfig MathJax predefined configuration to be used
     */
    public void setPredefinedConfig(String predefinedConfig) {
        this.preDefinedConfig = predefinedConfig;
    }

    /**
     * Minifies the MathJax config
     *
     * @param config The config to be minified
     * @return configuration string after formatting
     */
    private String minifyConfig(String config) {
        return config.replace("\n", "").replace(" ", "");
    }

    /**
     * Renders MathJax code that is found in the passed-in string
     *
     * @param text Text that contains the MathJax to be rendered
     */
    public void setText(String text) {
        this.mText = text;

        String configUrl;
        String html;
        String mimeType;
        try {
            configUrl = mContext.getResourceManager().getElement(ResourceTable.String_js_index_config).getString() + preDefinedConfig;
            html = mContext.getResourceManager().getElement(ResourceTable.String_html).getString();
            mimeType = mContext.getResourceManager().getElement(ResourceTable.String_mime_type).getString();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.printStackTrace();
            return;
        }
        load(String.format(html, config, configUrl, text), mimeType, CHARSET, "about:blank", "");
    }

    /**
     * Returns the MathJax code that was passed into using setText
     *
     * @return raw MathJax code
     */
    @Nullable
    public String getText() {
        return mText;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        return false;
    }
}
